# -*- coding: utf-8 -*-
# SSHexec 主程序

# 项目目录/
# ├── sshexec.py                    # 主程序
# └── src/                          # 源代码文件夹
#     ├── asyncssh/                 # 执行模块
#     │   └── asyncssh.py           # asyncssh文件
#     │   └── asyncssh_utils.py     # asyncssh工具文件
#     ├── transfer/                 # 传输模块
#     │   ├── transfer_check.py     # 传输检查文件
#     │   ├── transfer_utils.py     # 传输工具文件
#     │   └── transfer.py           # 传输文件
#     ├── check.py                  # 检查文件
#     ├── config.py                 # 配置文件
#     ├── core.py                   # 核心代码文件
#     ├── dict.py                   # 字典文件
#     ├── output.py                 # 打印结果文件
#     └── utils.py                  # 工具文件


# 系统或第三方模块
import os
import sys
from datetime import datetime

# 自定义模块
import src.core as core
import src.utils as utils
import src.check as check
import src.output as output
import src.config as config
import src.utils as utils

from src.utils import tlog, elog

def main():
    '''主程序'''

    # 初始化工具日志
    utils.init_tool_logger(config.DEFAULT_DIR_NAME_HISTORYS)
    tlog.debug(f"{ '-' * 50}分割线{ '-' * 50}")
    tlog.success("初始化工具日志成功")
    tlog.info(f"SSHExec工具开始执行，时间：{datetime.now()}")
    tlog.info(f"工作路径：{os.getcwd()}")
    tlog.info(f"命令行参数：{sys.argv}")
    tlog.info(f"日志目录：{config.DEFAULT_DIR_NAME_HISTORYS}，执行日志文件名：{config.DEFAULT_LOG_EXEC}")
    tlog.debug(f"{ '-' * 20}SSHExec工具 - 准备阶段{ '-' * 20}")


    # 检查颜色配置是否安全配置
    try:
        check.check_color_configs()
        tlog.success("[check] 检查颜色配置安全成功")
    except Exception as e:
        tlog.error(f"[check] 检查颜色配置安全失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("check.check_color_configs", f"检查颜色配置是否安全配置失败: {str(e)}")

    # 执行配置文件内容合规性检查
    try:
        check.check_configs()
        tlog.success("[check] 检查配置文件内容合规性成功")
    except Exception as e:
        tlog.error(f"[check] 检查配置文件内容合规性失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("check.check_configs", f"配置文件检查失败: {str(e)}")

    # 检查代码文件是否都存在
    try:
        check.check_files_exist()
        tlog.success("[check] 检查代码文件存在性成功")
    except Exception as e:
        tlog.error(f"[check] 检查代码文件存在性失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("check.check_files_exist", f"检查代码文件存在性失败: {str(e)}")

    # 参数解析
    try:
        args = core.parse_args()
        tlog.success("参数解析成功,解析结果: {args}")
    except Exception as e:
        tlog.error(f"参数解析失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("core.parse_args", f"参数解析失败: {str(e)}")

    # 参数合规性检查
    try:
        check.check_arguments(args)
        tlog.success("[check] 输入的参数合规性检查成功")
    except Exception as e:
        tlog.error(f"[check] 输入的参数合规性检查失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("check.check_arguments", f"输入的参数合规性检查失败: {str(e)}")

    # 执行打包历史记录
    if args.z:
        try:
            core.zip_latest_history(args)
            tlog.success(f"打包历史记录成功")
            tlog.info(f"SSHExec工具已退出")
            sys.exit(0)
        except Exception as e:
            tlog.error(f"打包历史记录失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
            utils.print_error_informantion_and_exit("core.zip_latest_history", f"打包历史记录失败: {str(e)}")
            
    # 执行全量检查函数（n个）
    try:
        check.check_all(args)
        tlog.success("[check] 执行全量检查函数成功")
    except Exception as e:
        tlog.error(f"[check] 执行全量检查函数失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("check.check_all", f"检查函数执行失败: {str(e)}")

    # 读取节点信息
    try:
        nodesinfos = core.read_nodes_infos(args.f)
        tlog.success("读取节点信息成功")
    except Exception as e:
        tlog.error(f"读取节点信息失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("core.read_nodes_infos", f"读取节点信息失败: {str(e)}")

    # 参数信息确认
    try:
        tlog.info(f"开始进行参数信息确认")
        core.arguments_confirm(args,nodesinfos)
        tlog.info("用户已核实通过参数信息")
    except Exception as e:
        tlog.error(f"参数信息确认失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("utils.arguments_confirm", f"参数信息确认失败: {str(e)}")

    
    
    tlog.debug(f"{'-' * 20}SSHExec工具 - 准备结束{'-' * 20}")
    tlog.debug(f"{'-' * 20}SSHExec工具 - 执行阶段{'-' * 20}")

    # “全局”开始时间计时
    global_start_time = datetime.now()
    tlog.info(f"全局开始时间: {global_start_time}")
    
    # 生成日志目录
    try:
        exec_log_dir = utils.create_exec_log_dir(args)
        tlog.success(f"生成日志目录成功: {exec_log_dir}")
    except Exception as e:
        tlog.error(f"生成日志目录失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("utils.create_exec_log_dir", f"生成日志目录失败: {str(e)}")
        sys.exit(1)

    # 初始化执行日志记录器
    try:
        utils.init_execution_logger(exec_log_dir)
        tlog.success(f"初始化执行日志记录器成功")
    except Exception as e:
        tlog.error(f"初始化执行日志记录器失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("log.init_execution_logger", f"配置loguru日志记录器失败: {str(e)}")


    # 进入asyncssh主执行器
    if args.c or args.s:
        import src.asyncssh.asyncssh as asyncssh
        tlog.info("进入asyncssh主执行器")
        tlog.debug(f"日志内容轮转到文件: {exec_log_dir}/{config.DEFAULT_LOG_EXEC}")
        final_results = asyncssh.execute_asyncssh(args, nodesinfos, exec_log_dir)
        tlog.success("asyncssh主执行器执行完成")

    # 进入transfer主执行器
    if args.u or args.d:
        import src.transfer.transfer as transfer
        tlog.info("进入transfer主执行器")
        tlog.debug(f"日志内容轮转到文件: {exec_log_dir}/{config.DEFAULT_LOG_EXEC}")
        final_results = transfer.execute_transfer(args, nodesinfos)
        tlog.success("transfer主执行器执行完成")


    # “全局”结束时间计时
    global_stop_time = datetime.now()
    tlog.info(f"全局结束时间: {global_stop_time}，全局执行时间: {round((global_stop_time - global_start_time).total_seconds(), 3)}秒")


    tlog.debug(f"{'-' * 20}SSHExec工具 - 执行结束{'-' * 20}")
    tlog.debug(f"{'-' * 20}SSHExec工具 - 整理阶段{'-' * 20}")


    # 格式化output.txt到Excel文件
    try:
        output.format_output_to_xlsx(exec_log_dir)
        tlog.success("格式化output.txt到Excel文件成功")
    except Exception as e:
        tlog.error(f"格式化output.txt到Excel文件失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("output.format_output_to_xlsx", f"打印output.txt到Excel文件失败: {str(e)}")

    # debug信息：输出results字典列表到xlsx文件
    try:
        output.format_dict_list_to_xlsx(final_results, exec_log_dir)
        tlog.success("格式化results字典列表到Excel文件成功")
    except Exception as e:
        tlog.error(f"格式化results字典列表到Excel文件失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("output.format_dict_list_to_xlsx", f"打印字典列表失败: {str(e)}")

    # 计算统计结果信息
    try:
        results_statistic = core.results_statistics(final_results, nodesinfos, args, global_start_time, global_stop_time)
        tlog.success("计算统计结果信息成功")
    except Exception as e:
        tlog.error(f"计算统计结果信息失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("core.results_statistics", f"计算统计结果信息失败: {str(e)}")

    # 格式化统计结果信息输出到终端
    try:
        output.format_statistic_results_to_terminal(results_statistic)
        tlog.success("格式化统计结果信息输出到终端成功")
    except Exception as e:
        tlog.error(f"格式化统计结果信息输出到终端失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("output.format_statistic_results_to_terminal", f"格式化统计结果信息输出到终端失败: {str(e)}")

    
    # 格式化统计结果信息输出到报告文件
    try:
        output.format_statistic_results_to_report(results_statistic, exec_log_dir, args)
        tlog.success("格式化统计结果信息输出到报告文件成功")
    except Exception as e:
        tlog.error(f"格式化统计结果信息输出到报告文件失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("output.format_statistic_results_to_report", f"格式化统计结果信息输出到报告文件失败: {str(e)}")

    # 保存执行资源文件
    try:
        core.save_execute_resource_files(args, exec_log_dir)
        tlog.success("保存执行资源文件成功")
    except Exception as e:
        tlog.error(f"保存执行资源文件失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("core.save_execute_resource_files", f"保存执行资源文件失败: {str(e)}")

    # 创建最新日志符号链接
    try:
        utils.create_latest_log_symlink()
        tlog.success("创建最新日志符号链接函数执行成功")
    except Exception as e:
        tlog.error(f"创建最新日志符号链接失败\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("utils.create_latest_log_symlink", f"创建最新日志符号链接失败: {str(e)}")


    tlog.debug(f"{'-' * 20}SSHExec工具 - 整理结束{'-' * 20}")

    # 退出SSHExec工具
    tlog.info(f"SSHExec工具已退出")
    sys.exit(0)



if __name__ == "__main__":
    """
    程序入口
    """
    try:
        # 进入主函数
        main()
    except KeyboardInterrupt:
        tlog.info(f"SSHExec工具主函数，用户手动中断执行")

    except Exception as e:
        tlog.error(f"SSHExec工具主函数，出现未被捕获的异常\n异常类型: {type(e)} \n异常参数: {e.args} \n异常信息: {e}")
        utils.print_error_informantion_and_exit("main", f"SSHExec工具主函数，出现未被捕获的异常: {str(e)}")


